/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package shaman.storage.impl.file;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import shaman.storage.api.Filter;
import shaman.storage.impl.stream.gather.PartStreamFactory;
import shaman.storage.impl.stream.size.SizeLimitInputStream;
import shaman.storage.impl.stream.size.SizeLimitOutputStream;
import shaman.storage.impl.stream.size.SizeMeasureOutputStream;
import shaman.storage.impl.util.OffsetMap;

/**
 *
 * @author dmitriy
 */
public class FilePartAccessor implements PartStreamFactory, Iterable<StoredBlock> {

    private int index=0;
    private final StorageFileAccessor acc;
    private final Filter postprocessor;
    private final String dateString;
    private final String fileType;
    private final String fileExt;
    private final long sizeLimit;
    private final OffsetMap<StoredBlock> offsetMap=new OffsetMap<StoredBlock>();

    private long writeOffset=0;

    private class BlockRegistratorOutputStream extends SizeMeasureOutputStream {

        private boolean closed;

        public BlockRegistratorOutputStream(OutputStream baseStream) {
            super(baseStream);
            closed=false;
        }

        @Override
        public void close() throws IOException {
            if (!closed)
            {
                closed=true;
                long length=getOffset();
                addBlock(new StoredBlock(writeOffset, length, fileType));
                writeOffset+=length;
            }
            super.close();
        }

    }

    public FilePartAccessor(StorageFileAccessor acc, String fileType, String fileExt, Filter postprocessor, String dateString, long sizeLimit) {
        this.acc=acc;
        this.fileType=fileType;
        this.fileExt=fileExt;
        if (postprocessor==null)
            throw new RuntimeException("postprocessor must not be null!");
        this.postprocessor=postprocessor;
        this.dateString=dateString;
        this.sizeLimit=sizeLimit;
    }

    public int getBlockSize() {
        return FileBackup.FILE_BLOCK_SIZE;
    }

    public InputStream getInputStream(long offset) throws IOException {
        int blockIdx=offsetMap.getIndex(offset);
        StoredBlock block=offsetMap.getItemAt(blockIdx);
        InputStream baseStream = acc.fetchFile(FileBackup.getFileName(dateString, fileType, blockIdx, fileExt), offset-block.getOffset(), block.getLength());
        InputStream limitStream = new SizeLimitInputStream(baseStream, block.getLength());
        InputStream filtStream = postprocessor.getInputStream(limitStream);
        return filtStream;
    }

    public OutputStream getNextOutputStream() throws IOException {
        OutputStream baseStream = acc.storeFile(FileBackup.getFileName(dateString, fileType, index++, fileExt));
        OutputStream limitStream = new SizeLimitOutputStream(baseStream, sizeLimit);
        OutputStream filtStream = postprocessor.getOutputStream(limitStream);
        return new BlockRegistratorOutputStream(filtStream);
    }

    public void addBlock(StoredBlock blk)
    {
        offsetMap.add(blk.getOffset(), blk);
    }

    public Iterator<StoredBlock> iterator() {
        return offsetMap.iterator();
    }
    
}
